#ifndef __DATA_STORAGE_H__
#define __DATA_STORAGE_H__

#include "Player/World/World.h"
#include "Player/World/Ball.h"
#include "Common/World/Point.h"
#include "Common/World/Angle.h"
#include "Common/World/Types.h"
#include "Common/Interfaces/Commands.h"
#include "Evaluating/EvaluatingPanesMap.h"
#include "Evaluating/EvaluatingPlayerList.h"
#include "Player/Formation.h"
#include "CommonFunctions.h"

//makro na zjednodusenie pouzitia v programe
#define DATA_STORAGE DataStorage::getInstance()

//model sveta
extern World* world;

//rozhranie pre posielanie prikazov na server
extern CommandsInterface* commandGenerator;


/**
 * V tejto triede su informacie dostupne hracovi. Singleton, iba jedna instancia v programe.
 * Pouziva sa pomocou DataStorage::getInstance() resp. makro DATA_STORAGE
 * Bude to nieco ako ulozisko premennych, ktore su "teraz" v triedach a metodach.
 * Model sveta, parser sprav... Upravit ako sa to sem bude davat..
 * Predstava je ze jednotlive spravania budu mat struktury, kde budu potrebne informacie.
 * Vid turnNeck.
 *
 * Mozny navrh na diskusiu ci nechat pristup k zlozkam priamo alebo pomocou metod get a set.
 * Pripadne tie struktury dat do samostatneho suboru.?
 */

#define BALL_HISTORY_COUNT 7
#define FIELDWIDTH 104

// Aka je minmalna pozadovane (ocakavana) rychlost lopty na brankovej ciare, ktora sa detekuje ako strela na branu?
#define SPEED_ON_GOAL_LINE_MIN 0.05f



class DataStorage
{
public:

	GoalieKickOff goalieKickOff;

	int NumberOfEnemiesAround(const Point p,float dist=5.0f) const;

	static DataStorage& getInstance();
	
	//pouzite globalnu premennu world a commandGenerator
	//CommandsInterface* commandGenerator;
	//World* world;

	//informacie suvisiace s otacanim krku
	struct turnNeckStruct 
	{	
		int timeOfLastTurnNeck; // Posledny cyklus, ked hrac otocil krkom.
		Point futurePosition; //co tieto dalsie znamenaju?
		Point futureMyPosition;
		float nextTurn;
		bool avoidNextCorrection; //zabranenie dalsim korekciam
		int changeView;
		int neckDirection;
		float correction;
	} turnNeck;

	//informacie suvisiace s chytenim loppty brankarom
	struct goalieCatchStruct 
	{	
		int goalieCatchBan;
	} goalieCatch;
	
	//informacie suvisiace s veducim hry
	struct {
		bool attentionToSet;
		bool amILeader;
		int leaderUniform;
		int lastSendTime;
		int lastChangeTime;
		int casZmenyVeduceho;
		int casZmenyFormacie;
		LPT_FormationType currentFormation;
	} leadership;
	
	//cislo hraca
	int myUniform;

	//pozicia hraca
	Point myPosition;

	//Pozicia lopty
	Point ballPosition;

	// Vzdielnost medzi loptou a hracom (nemusi byt ta ista ako DATA_STORAGE.ballDiff!)
	float ballDistance;

	// Cyklus kedy hrac skutocne videl loptu
	int lastValidBallTime;

	// Posledna informacia o skutocnej videnej lopte zo servera
	Ball* lastValidBallInfo;
	
	//nastavi sa, ci sa ma lopta ignorovat
	bool ignoreBall;
	
	// Vektor od hraca k lopte
	Vector ballDiff;

	//informacie suvisiace s PassToRandomUmbrellaPositionBehaviour
	Point umbrellaPositions[4];

	// Model pohybu lopty (historia[N] + aktualny stav[1] + predikcia[N])
	Ball* ballStates[BALL_HISTORY_COUNT];

	// Index bunky, kde je ulozena aktualna informacia o lopte
	int actualBallStateIndex;

	//mozeme kopnut do lopty?
	bool ballKickable;

	// Rola hraca
	PlayerRole playerRole;

	//synchronizacia
	SynchroMode nextSynchMode;

	SynchroMode GetNextSynchMode()
	{
		return nextSynchMode;
	}
	void SetNextSynchMode(SynchroMode mode)
	{
		nextSynchMode = mode;
	}
	//synchronizacia

	// Uhol scanovania pred vykopavanim
	float scanBeforeKickOffAngle;

	// Pomocne premenne pri prihravani
	double lfTmpX, lfTmpY;

	// Bod pre driblovanie, ktory sa pouziva nielen pre urcenie optimalneho bodu pre dribling
	double lfDribbleX, lfDribbleY;

	//formacia
	Formation formation;

	// ziska stav formacie
	int GetFormation(const char* formation);

	//kolko cyklov trvaju hracie mody
	int cornerKickModeDuration;
	int freeKickModeDuration;
	int indFreeKickModeDuration;
	int kickInModeDuration;

	//METODY

	// Vypocita a vrati vzdialenost k branke
	float DistanceToGoal(const Point&);
		
	// Vrati NULL, ak superov brankar nie je v hracovom svete
	Player* GetEnemyGoalie();
			
	// Vrati NULL, ak nas brankar nie je v hracovom svete Peter Csfalvay (LOPTOI)
	Player* GetOurGoalie() ;				

	// Vrati vzdialenost k nablizsiemu superovemu hracovi
	float GetNearestEnemyDistance(const Point& target);

	// Vrati najblizsi index spoluhraca
	int GetNearestFriend(const Point& target);
						
	// Vrati vzdialenost k najblizsiemu spoluhracovi
	float GetNearestFriendDistance(const Point& target);

	// Vrati domovsku poziciu
	Point GetHomePos();	

	// vrati liniu ofsajdu
	float GetOffsideLine();

	//je hrac v ofsajde?
	bool InOffsidePos();

	// Nachadza sa bod v pokutovom uzemi?
	bool InPenaltyArea(const Point p);

	//ci je mozne kopnut do lopty
	bool IsBallKickable();

	// Mam kopnut do lopty mimo modu PlayOn?
	bool ShouldKickIn();

	bool DependentForBall();

	// Vrati supera najblizsieho k lopte
	int NearEnemy(int* pCycles);

	// Vrati naseho najblizsieho hraca k lopte. Vrati -1, ak som to ja.
	int NearFriend(int* pCycles);

	//smeruje lopta na nasu branu?
	bool BallHeadingOnOurGoal(float tolerance = 10.f);

	//je lopta na nebezpecnej pozicii?
	bool DangerousBall();
	
private:
	DataStorage();
	DataStorage(const DataStorage& d);
	DataStorage &operator = (const DataStorage& d);
};



#endif
